﻿using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine.Playables;
using UnityEngine.Timeline;

public static class JumpabelManager
{
    private static List<JumpableTrack> JumpableTrackDelayList = new List<JumpableTrack>();
    public static void RegisterDelayInjdectJumpableTrack(JumpableTrack track)
    {
        JumpableTrackDelayList.Add(track);
    }

    public static void JumpableTrackDelayInjdect()
    {
        foreach (JumpableTrack track in JumpableTrackDelayList)
        {
            track.Inject();
        }
    }

    private static Dictionary<int, DirectorInfo> DictOfDirectors = new Dictionary<int, DirectorInfo>();

    private static bool CheckBeforeProcess(PlayableDirector director, double originTime, double destinationTime)
    {
        if (null == director)
        {
            return false;
        }

        if (originTime == destinationTime)
        {
            return false;
        }

        if (originTime < 0 || originTime < 0)
        {
            return false;
        }

        if (originTime > director.duration || originTime > director.duration)
        {
            return false;
        }

        return true;
    }

    public static void OnDirectorJump(PlayableDirector director, double originTime, double destinationTime)
    {
        //Check
        if (!CheckBeforeProcess(director, originTime, destinationTime))
        {
            return;
        }

        List<PlayableBehaviour> list;
        IJumpableBehaviour jumpable;
        Type type;

        bool forward = false;
        if (originTime < destinationTime)
        {
            forward = true;
        }

        List<TrackInfo> trackInfos = GetTracksByDirector(director);
        foreach (TrackInfo track in trackInfos)
        {
            list = SortPlayableAsset(track.behaviours);

            foreach (PlayableBehaviour playable in list)
            {
                type = playable.GetType();
                if (!typeof(IJumpableBehaviour).IsAssignableFrom(type))
                {
                    continue;
                }

                jumpable = (IJumpableBehaviour)playable;

                if (forward)
                {
                    if (jumpable.TimeInfo.start > destinationTime || jumpable.TimeInfo.end < originTime)
                    {
                        continue;
                    }
                }
                else
                {
                    if (jumpable.TimeInfo.start > originTime || jumpable.TimeInfo.end < destinationTime)
                    {
                        continue;
                    }
                }

                jumpable.OnDirectorJump(forward, originTime, destinationTime);

            }
        }
    }


    public static List<PlayableBehaviour> SortPlayableAsset(List<PlayableBehaviour> list, bool descending = false)
    {
        //list.Sort((x, y) =>
        //{
        //    IJumpableBehaviour xa = (IJumpableBehaviour)x;
        //    IJumpableBehaviour ya = (IJumpableBehaviour)y;

        //    return xa.TimeInfo.start.CompareTo(ya.TimeInfo.start);
        //});

        List<PlayableBehaviour> sorted;
        if (!descending)
        {
            sorted = list.OrderBy(item =>
            {
                IJumpableBehaviour a = (IJumpableBehaviour)item;
                return a.TimeInfo.start;
            }).ToList();
        }
        else
        {
            sorted = list.OrderByDescending(item =>
            {
                IJumpableBehaviour a = (IJumpableBehaviour)item;
                return a.TimeInfo.start;
            }).ToList();
        }

        return sorted;
    }

    public static List<TrackInfo> GetTracksByDirector(PlayableDirector director)
    {
        if (null == director)
        {
            //非法参数
            return null;
        }

        //Direcotr
        DirectorInfo directorInfo = null;
        int directorId = director.GetInstanceID();
        if (!DictOfDirectors.ContainsKey(directorId))
        {
            //未找到PlayableDirector
            return null;
        }

        directorInfo = DictOfDirectors[directorId];

        return directorInfo.trackInfos.Values.ToList();
    }

    public static bool AddPlayableAsset(PlayableDirector director, TrackAsset track, PlayableBehaviour behaviour)
    {
        if (null == director || null == track || null == behaviour)
        {
            //非法参数
            return false;
        }

        //Direcotr
        DirectorInfo directorInfo = null;
        int directorId = director.GetInstanceID();
        if (DictOfDirectors.ContainsKey(directorId))
        {
            directorInfo = DictOfDirectors[directorId];
        }
        else
        {
            directorInfo = new DirectorInfo();

            DictOfDirectors.Add(directorId, directorInfo);
        }

        //Track
        TrackInfo trackInfo = null;
        int trackId = track.GetInstanceID();
        if (directorInfo.trackInfos.ContainsKey(trackId))
        {
            trackInfo = directorInfo.trackInfos[trackId];
        }
        else
        {
            trackInfo = new TrackInfo();

            directorInfo.trackInfos.Add(trackId, trackInfo);
        }

        //Behaviour
        if (trackInfo.behaviours.Contains(behaviour))
        {
            //已经存在
            return false;
        }

        trackInfo.behaviours.Add(behaviour);

        return true;
    }

}
